#include "ota_version.h"
#include "ota_http_curl.h"
#include "unistd.h"
#include "cJSON.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <sys/reboot.h>
#include "log.h"

/**
 * 计算文件的SHA1哈希值
 * @param filepath 文件路径
 * @return SHA1哈希值字符串（需要调用者释放内存）
 */
char* generate_file_sha1(const char* filepath) {
    FILE* file = fopen(filepath, "rb");
    if (!file) {
        return NULL;
    }
    
    SHA_CTX sha1_ctx;
    SHA1_Init(&sha1_ctx);
    
    unsigned char buffer[8192];
    unsigned char hash[SHA_DIGEST_LENGTH];
    char* result = NULL;
    size_t bytes_read;
    
    // 读取文件内容并更新哈希计算
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
        SHA1_Update(&sha1_ctx, buffer, bytes_read);
    }
    
    // 完成哈希计算
    SHA1_Final(hash, &sha1_ctx);
    fclose(file);
    
    // 将二进制哈希值转换为十六进制字符串
    result = (char*)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!result) {
        return NULL;
    }
    
    for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
        sprintf(&result[i * 2], "%02x", hash[i]);
    }
    
    result[SHA_DIGEST_LENGTH * 2] = '\0';
    return result;
}



/**
 * @brief 检查并下载程序
 * 
// 1 查询远端的版本信息（json） 
//2  解析json提取版本号
// 3 用本地版本号和远端的版本号进行对比
// 4 如果本地版本号下  触发下载 
//5  根据地址下载程序文件 
//6  验证程序文件  
//          生成该程序文件的sha码 和远端的sha码进行对比
// 7如果验证通过  
//           无法自己把自己的程序换掉 
//8 重启关闭
//  ---  替换程序文件   shell 脚本
// --启动

 */
int ota_version_checkAndUpdate(void)
{
// 1 查询远端的版本信息（json） 
response_body_t *response_body = ota_http_curl_get_string(OTA_URL);
if (response_body == NULL)
{
  return  -1;
}
//2  解析json提取版本号
cJSON *root = cJSON_Parse(response_body->str);
cJSON *major_cjson = cJSON_GetObjectItem(root, "major");
cJSON *minor_cjson = cJSON_GetObjectItem(root, "minor");
cJSON *patch_cjson = cJSON_GetObjectItem(root, "patch");
 int ota_major= major_cjson->valueint;
 int ota_minor= minor_cjson->valueint;
 int ota_patch= patch_cjson->valueint;
log_info(" ota version:%d.%d.%d\n",ota_major,ota_minor,ota_patch);
// 3 用本地版本号和远端的版本号进行对比
if(MAJOR > ota_major ||( ota_major== MAJOR && MINOR >   ota_minor)  || ( ota_major== MAJOR && MINOR== ota_minor && PATCH >=   ota_patch)  )
{
    cJSON_Delete(root);
    free(response_body->str);
    free(response_body);
    log_info(" 本地已经是最新版本了 ..");
    return 0;
}

log_info("  发现最新版本 ..开始下载 ..");
// 4 如果本地版本号下  触发下载 
//5  根据地址下载程序文件 
 int ret=  ota_http_curl_downloadFile(OTA_DOWNLOAD_URL,OTA_DOWNLOAD_PATH);
 if(ret==-1)
 {
    cJSON_Delete(root);
    free(response_body->str);
    free(response_body);
    log_error(" 下载最新版本失败 ..");
    return -1;
 }

//6  验证程序文件  
//          生成该程序文件的sha码 和远端的sha码进行对比
  char* sha_local= generate_file_sha1(OTA_DOWNLOAD_PATH);
  cJSON *sha1_cjson = cJSON_GetObjectItem(root, "sha1");
  char *sha_remote= sha1_cjson->valuestring;
  if(strcmp(sha_local,sha_remote)==0)  
  {
  // 7如果验证通过  
  //           无法自己把自己的程序换掉 
  //8 重启关闭
    log_info(" 本地文件验证成功 ..");
    reboot(RB_AUTOBOOT);
    return 0;
  }
  
    
    cJSON_Delete(root);
    free(response_body->str);
    free(response_body);
    free(sha_local);
    unlink(OTA_DOWNLOAD_PATH);//删除文件
    log_error(" 验证失败 ..");
    return -1;
 
    
}



/**
 * @brief ota 程序启动
 */
void ota_version_start(void)
{
    
    while(1)
    {
        sleep( 4*60*60);
        ota_version_checkAndUpdate();

    }

}

/**
 * @brief 打印当前版本号
 */
void ota_version_print(void)
{
    printf(" 当前版本:%d.%d.%d\n",MAJOR,MINOR,PATCH);
}